# ifndef __Map_H_
# define __Map_H_

//
// Map.h
//
// Declarations of all map-related types.
//

# include "fvector.h"

# include "PtAlgo.h"
# include "RgnKind.h"
# include "Units.h"
# include "LoadStatus.h"

const DWORD c_dwUnknownRoadId = (DWORD) (-1);
const DWORD c_dwUnknownNodeId = (DWORD) (-1);
const size_t c_cUnknownPoint  = (size_t) (-1);
const size_t c_cUnknownPos    = (size_t) (-1);
const size_t c_cUnknownLine   = (size_t) (-1);
const size_t c_cUnknownOffset = (size_t) (-1);


//
// The data used for postal address attributes.
//
struct pa_item_t {
	string_t strName;

	// These fields are used for temporary purposes.
	size_t cIndex;
	bool bMarked;

	bool bDeleted;
	bool IsDeleted () const {return bDeleted;}

	pa_item_t () : cIndex (0), bDeleted (false) {}

	// Used internally for deep copying.
	void _SaveCopyRef (const pa_item_t * _pai) {* reinterpret_cast<const pa_item_t **> (& cIndex) = _pai;}
	const pa_item_t * _GetCopyRef () const {return reinterpret_cast<const pa_item_t *> (cIndex);}
};

struct pa_item_a_t : public pa_item_t {
	string_t strAbbrevName;
};

// Country.
struct country_t : public pa_item_a_t {
	size_t cRegions;
};

typedef std::list<country_t> countries_t;

// Region.
struct region_t : public pa_item_a_t {
	country_t * pCountry;
	size_t cCities;

	bool IsDeleted () const {return bDeleted || ! pCountry || pCountry->IsDeleted ();}

	region_t () : pCountry (NULL) {}
};

typedef std::list<region_t> regions_t;

// City.
struct city_t : public pa_item_t {
	region_t * pRegion;

	// These fields are used for temporary purposes.
	ULONG cObjects   : 31,
	      bLocatable : 1;
	ULONG cObjectsButThis;
	ULONG cAddressObjects;

	bool IsDeleted () const {return bDeleted || ! pRegion || pRegion->IsDeleted ();}

	city_t () : pRegion (NULL), cObjects (0), bLocatable (0) {}
};

typedef std::list<city_t> cities_t;

// Zip code.
struct zip_t : public pa_item_t {};

typedef std::list<zip_t> zips_t;

// Highway (for exit facilities).
struct highway_t : public pa_item_t {
	region_t * pRegion;

	bool IsDeleted () const {return bDeleted || ! pRegion || pRegion->IsDeleted ();}

	highway_t () : pRegion (NULL) {}
};

typedef std::list<highway_t> highways_t;

struct map_t;
struct type_desc_t;
struct file_ref_t;
class CTypeSet;

# include "RGNodes.h"
# include "WTR.h"


//
// The optional properties of elements.
//
struct rgn_element_extra_t {
	// Routing and house numbering.
	point_extras_t PointExtras;

	// Tracks only: speed, altitude etc.
	trackpoints_t TrackPoints;
	float GetSpeed (size_t _cPoint, const points_t & _points) const;

	mutable DWORD dwTmp;

	rgn_element_extra_t () {}
};

class rgn_element_extra_ptr {
  public:
	rgn_element_extra_ptr () : m_p (NULL) {}
	rgn_element_extra_ptr (const rgn_element_extra_ptr & _other) : m_p (NULL) {
		if (_other.m_p) {
			_create ();
			* m_p = * _other.m_p;
		}
	}
	~rgn_element_extra_ptr () {
		if (m_p) // NOTE: this 'if' is not necessary but inserted just for speed optimization.
			delete m_p;
	}

	rgn_element_extra_ptr & operator = (const rgn_element_extra_ptr & _other) {
		if (_other.m_p) {
			_create ();
			* m_p = * _other.m_p;
		}
		return * this;
	}

	const rgn_element_extra_t * operator -> () const {_create (); return m_p;}
	      rgn_element_extra_t * operator -> ()       {_create (); return m_p;}

	const rgn_element_extra_t & operator *  () const {_create (); return * m_p;}
	      rgn_element_extra_t & operator *  ()       {_create (); return * m_p;}

	bool operator ! () const {return m_p == NULL;}
	operator bool () const {return m_p != NULL;}

	void swap (rgn_element_extra_ptr & _other) {std::swap (m_p, _other.m_p);}

  private:
	void _create () const {
		if (m_p == NULL)
			m_p = new rgn_element_extra_t;
	}

	mutable rgn_element_extra_t * m_p;
};


//
// Object's element: 'elementary' polygon w/o self-intersections or polyline
// defined for givel zoom level.
//
struct rgn_element_t {
	// Nodes of polygon or polyline.
	// NOTE: no self-intersections for polygons is assumed.
	points_t points;
	// The bounding rectangle.
	rect_t   rectBound;
	// The zoom level.
	unsigned char cLevel;

	// For polygons only - whether is it inner 'hole' in another element.
	bool     bHole;

	// True for deleted elements.
	bool     bDeleted;

	// For polylines only - the linear size in degrees (latitude scale).
	// For polygons only - the area in degrees^2 (latitude scale x longitude scale).
	float    fLengthOrArea;

	// The reference to source file.
	size_t   cFileOffset;

	//
	// Optional properties.
	//
	rgn_element_extra_ptr pExtra;

	rgn_element_t () : bDeleted (false), bHole (false), fLengthOrArea (0) {}

	void swap (rgn_element_t & _other);

	bool operator == (const rgn_element_t & _other) const {
		return cLevel == _other.cLevel && bHole == _other.bHole && points == _other.points;
	}

	bool IsHoleOf (const rgn_element_t & _Outer) const;

	void ReleaseRGNodes ();
	void AddRefRGNodes ();

	void RemoveRepeatingPoints ();

	rgnode_t * GetNextNode (const rgnode_t * _pNode, bool _bForward) const;
	rgnode_t * GetPrevNode (const rgnode_t * _pNode, bool _bForward) const {return GetNextNode (_pNode, ! _bForward);}
	size_t FindNode (const rgnode_t * _pNode) const;
	bool   HasNode  (const rgnode_t * _pNode) const;
};

typedef fvector<rgn_element_t> rgn_elements_t;


//
// Object's origin: coordinates of point defined for givel zoom level.
//
struct rgn_origin_t {
	// The coordinates.
	point_t point;
	// The zoom level.
	unsigned char cLevel;

	// True for deleted origins.
	bool bDeleted;

	// The reference to source file.
	size_t  cFileOffset;

	rgn_origin_t () : bDeleted (false) {}

	void swap (rgn_origin_t & _other);

	bool operator == (const rgn_origin_t & _other) const {
		return cLevel == _other.cLevel && point == _other.point;
	}
};

typedef fvector<rgn_origin_t> rgn_origins_t;


//
// The optional properties of objects.
//
struct rgn_extra_t {
	//
	// POI address.
	//
	city_t * pCity;
	string_t strNumber;
	string_t strStreetDesc;
	zip_t *  pZip;

	//
	// Contact info.
	//
	string_t strPhone;
	string_t strFax;
	string_t strEmail;
	string_t strWebPage;

	string_t strDescription;

	//
	// Exits with facilities (points only).
	//
	highway_t * pHighway;
	// TODO: the facilities list, overnight parking etc

	//
	// The routing data (polylines only).
	//
	DWORD dwRoadID;

	union {
		WORD wRouteParams_Basic; // (for backward compatibility only)
		DWORD dwRouteParams;

		struct {
			WORD fSpeedLimit   : 3,
			     fRouteClass   : 3,
			     bOneWay       : 1,
			     bToll         : 1,
			     bNoEmergency  : 1,
			     bNoDelivery   : 1,
			     bNoCar        : 1,
			     bNoBus        : 1,
			     bNoTaxi       : 1,
			     bNoPedestrian : 1,
			     bNoBicycle    : 1,
			     bNoTruck      : 1;

			WORD bNoThrough    : 1;
			     // Left: 15 bits
		};
	};
	bool HasAnyRoutingParam () const {return dwRouteParams != 0;}
	bool HasSpeedOrClass () const {return fSpeedLimit != 0 || fRouteClass != 0;}

	DWORD dwManeuverType;

	BYTE bNoJoin : 1; // Do not join this road with others in any automatic tools.

	//
	// Entry point for RGN.
	//

	BYTE bEntryPointDefined : 1;
	point_t ptEntryPoint;
	bool IsEntryPointDefined () const {return bEntryPointDefined;}

	//
	// All unsupported properties stored as multi-line string (each line is <key>=<value>).
	//
	string_t strExtra;

	//
	// Extra data for waypoints/tracks/routes.
	//
	wtr_extra_t wtr;

	rgn_extra_t () :
		pCity (NULL), pZip (NULL), pHighway (NULL),
		dwRoadID (-1), dwRouteParams (0), dwManeuverType (0),
		bNoJoin (0), bEntryPointDefined (0)
	{}
};

class rgn_extra_ptr {
  public:
	rgn_extra_ptr () : m_p (NULL) {}
	rgn_extra_ptr (const rgn_extra_ptr & _other) : m_p (NULL) {assert (_other.m_p == NULL);}
	~rgn_extra_ptr () {
		if (m_p) // NOTE: this 'if' is not necessary but inserted just for speed optimization.
			delete m_p;
	}

	rgn_extra_ptr & operator = (const rgn_extra_ptr & _other) {
		if (_other.m_p) {
			_create ();
			* m_p = * _other.m_p;
		}
		return * this;
	}

	const rgn_extra_t * operator -> () const {_create (); return m_p;}
	      rgn_extra_t * operator -> ()       {_create (); return m_p;}

	const rgn_extra_t & operator *  () const {_create (); return * m_p;}
	      rgn_extra_t & operator *  ()       {_create (); return * m_p;}

	bool operator ! () const {return m_p == NULL;}
	operator bool () const {return m_p != NULL;}

	void swap (rgn_extra_ptr & _other) {std::swap (m_p, _other.m_p);}

  private:
	void _create () const {
		if (m_p == NULL)
			m_p = new rgn_extra_t;
	}

	mutable rgn_extra_t * m_p;
};

//
// Object of map: one or more elements.
//
struct rgn_t {
  private:
	// Disable copy semantics.
//	rgn_t (const rgn_t &);
	void operator = (const rgn_t &);

  public:
	//
	// Rgn's type.
	//

	const type_desc_t * pTypeDesc;
	// NOTE: Unknown types can't be found in CTypeDesc table; so, they should be saved here.
	USHORT ushType;
	// Any value from RGN_KIND.
	BYTE Kind;

	RGN_KIND GetKind () const {return static_cast<RGN_KIND> (Kind);}

	void SetType (const type_desc_t * _pTD, USHORT _ushType, BYTE _Kind) {
		pTypeDesc = _pTD;
		ushType   = _ushType;
		Kind      = _Kind;
		// NOTE: track has no type and uses pTypeDesc/ushType to store color/width.
		assert (! IsTrack ());
	}
	void SetType (const CTypeSet * _pTypeSet, USHORT _ushType, BYTE _Kind);
	const type_desc_t * GetTypeDesc () const;
	USHORT GetType () const {
		if (IsTrack ())
			return 0;
		return ushType;
	}

	bool IsPoint    () const;
	bool IsPolygon  () const;
	bool IsPolyline () const;

	bool IsRoad () const;

	bool HasRGNodes () const;

	void SetWaypointType () {Kind = rkPoint;    dwFlags |= rgn_t::fWaypointOrTrack;}
	void SetTrackType    () {Kind = rkPolyline; dwFlags |= rgn_t::fWaypointOrTrack;}
	void SetRouteType    () {Kind = rkPolyline; dwFlags |= rgn_t::fRoute;}

	bool IsWTR      () const {return (dwFlags & (fWaypointOrTrack | fRoute)) != 0;}
	bool IsWaypoint () const {return (dwFlags & fWaypointOrTrack) != 0 && Kind == rkPoint;}
	bool IsTrack    () const {return (dwFlags & fWaypointOrTrack) != 0 && Kind == rkPolyline;}
	bool IsRoute    () const {return (dwFlags & fRoute)           != 0 && Kind == rkPolyline;}

	bool IsAttachment () const;
	bool IsVisible    () const;
	bool IsImmutable  () const {return IsDeleted () || IsAttachment ();}
	bool IsMutable    () const {return ! IsImmutable ();}

	//
	// Other attributes.
	//

	bool GetDirection (DWORD _dwStartNodeID, DWORD _dwEndNodeID, bool & _bForward) const;
	rgnode_t * GetNextNode (const rgnode_t * _pNode, bool _bForward) const;
	rgnode_t * GetPrevNode (const rgnode_t * _pNode, bool _bForward) const {return GetNextNode (_pNode, ! _bForward);}
	bool HasNode (const rgnode_t * _pNode) const;

	enum {
		// NOTE: it should correspond to layer_t::cDeletedRgns.
		fDeleted             = 0x01,
		// Affects on properties visualisation.
		fModified            = 0x02,

		// True if ptLabel is filled out.
		fPtLabelDefined      = 0x04,

		// Read-only object from attached waypoints/tracks/routes file.
		fWaypointOrTrack     = 0x08,
		fRoute               = 0x10,

		// True for directed polylines.
		fDirIndicator        = 0x20,
		// True for indexed city.
		fIndexedCity         = 0x40,
		// True for objects not to be included to the search index.
		fDontFind            = 0x80
	};
	BYTE dwFlags;

	bool IsDeleted () const;
	void Delete   (map_t & _map, bool _bReleaseRGNodes = false);
	void Undelete (map_t & _map, bool _bAddRefRGNodes  = false);

	//
	// The object's label.
	//

	string_t strLabel;

	// Position & orientation of the text (for visualization).
	point_t ptLabel;
	// NOTE: in degrees, from -90 to 90.
	signed char chLabelAngle;

	// Text width in pixels divided by 8 (rounded up).
	unsigned char ucLabelWidthBy8;
	// Text height in pixels.
	unsigned char ucLabelHeight;

	//
	// The level to which definition of all elements extends.
	// (EndLevel= in Polish format).
	//
	unsigned char uchEndLevel : 5;

	// Use for temporary object mark-up.
	unsigned char bTemporary : 1;
	// Extended flags
	unsigned char ucExtendedFlags : 2;

	//
	// Object's elementary polygons or polylines (DataX= in Polish format).
	// NOTE: the polygon inner elements should follow their outer ones.
	//
	rgn_elements_t elements;
	size_t GetElements () const;
	size_t GetElementsInLevel (size_t _cLevel) const;
	rgn_element_t       * GetNonDeletedElement (size_t _c, size_t _cLevel = -1);
	const rgn_element_t * GetNonDeletedElement (size_t _c, size_t _cLevel = -1) const;

	//
	// Rgn's points (OriginX= in Polish format).
	//
	rgn_origins_t origins;
	size_t GetOrigins () const;
	size_t GetOriginsInLevel (size_t _cLevel) const;

	//
	// Any custom comment. Multi-line is allowed.
	// NOTE: each line should begin with semicolon.
	//
	string_t strComment;
	void AddCommentLine (const char * _strLine);

	//
	// Optional properties.
	//
	rgn_extra_ptr pExtra;


	//
	// Secondary attributes.
	//

	// The bounding rectangle.
	rect_t rectBound;

	// Distance^2 between max distant points.
	float fSize2;

	// Used to sort RGN80.
	float fAveElementArea;

	//
	// Source file attributes.
	//

	// Reference to the source file.
	// NOTE: valid until fModified flag is set.
	size_t cBeginPos;
	size_t cEndPos;
	size_t cFileLine;

	// The next rgn in load order.
	rgn_t * pNextRgn;
	// Reference to the attached file (for waypoints and tracks).
	file_ref_t * pFileRef;

	rgn_t () :
		pTypeDesc (NULL),
		ushType (0),
		Kind (rkPoint),
		uchEndLevel (0),
		ucLabelWidthBy8 (0),
		ucLabelHeight (0),
		fSize2 (0),
		fAveElementArea (0),
		cBeginPos (0),
		cEndPos (0),
		cFileLine (0),
//		cOrdinal (0),
		pNextRgn (NULL),
		dwFlags (0),
		pFileRef (NULL),
		ucExtendedFlags (0)
	{}

	bool Contains (const point_t & _point, float _fE) const;
	bool IntersectsSegment (const point_t & _ptStart, const point_t & _ptEnd) const;

	// Updates bounding rect, area, size etc
	// NOTE: _bRefereshDrawOrder=true invalidates iterators in containing layer.
	void RefreshAttributes (map_t & _map, bool _bRefereshDrawOrder = true);

	// Reorder inner polygons to conform inner/outer order. bHole is assumed to be set.
	void ReorderHoles ();

	// NOTE: used to sort polygons while updating the draw order of polylines.
	bool operator < (const rgn_t & _other) const {
		return fAveElementArea > _other.fAveElementArea;
	}
/*
	bool operator == (const rgn_t & _other) const {
		if (fAvePartArea != _other.fAvePartArea)
			return false;
		return elements == _other.elements;
	}*/

	void ReleaseRGNodes ();
	void AddRefRGNodes ();
};

typedef std::list<rgn_t> rgns_t;

float GetRgnSize (const rgn_t & _rgn);


//
// Rendering layer: list of objects of the same kind.
// NOTE: all objects in the layer are considered to be drawn from first to last one.
// In practice, there are just 3 layers: points, polylines, and polygons.
// And just polygons may overlap, so the order of drawing inside their layer is meaningful for them.
//
struct layer_t {
	rgns_t rgns;
	// Total count of objects, including deleted ones.
	size_t cRgns;
	size_t cDeletedRgns;

	layer_t () : cRgns (0), cDeletedRgns (0) {}

	void clear () {
		rgns.clear ();
		cRgns = 0;
		cDeletedRgns = 0;
	}

	void swap (layer_t & _other) {
		rgns.swap (_other.rgns);
		std::swap (cRgns, _other.cRgns);
		std::swap (cDeletedRgns, _other.cDeletedRgns);
	}
};


//
// The source file description.
//
struct file_ref_t {
	// File name including full path.
	string_t strFileName;
	// True for deleted files.
	bool bDeleted;
	// True for attached files.
	bool bAttachment;
	// True for visible attachments.
	bool bVisible;
	// True for showing track's direction.
	bool bShowDirection;

	file_ref_t () : bDeleted (false), bAttachment (true), bVisible (true), bShowDirection (false) {}

//	void clear () {
//		this->strFileName = "";
//	}

	void swap (file_ref_t & _other) {
		this->strFileName.swap (_other.strFileName);
		std::swap (this->bDeleted,       _other.bDeleted);
		std::swap (this->bAttachment,    _other.bAttachment);
		std::swap (this->bVisible,       _other.bVisible);
		std::swap (this->bShowDirection, _other.bShowDirection);
	}

	// Used by DeleteAttachment().
	virtual void * DetachData () {return NULL;}
	virtual void AttachData (void * _pData) {assert (_pData == NULL);}
	virtual void FreeData   (void * _pData) {assert (_pData == NULL);}
};

typedef std::list<file_ref_t> file_refs_t;

//
// The attached map renderer.
//
struct renderer_base_t : public file_ref_t {
	// The bounding rectangle. NOTE: it is shifted with ptCorrectionShift from 'basic' calibration.
	rect_t  rect;
	// The correction shift of the image against 'basic' calibration.
	point_t ptCorrectionShift;

	// True for additional alpha-blended images rendered for overlay areas.
	bool bOverlay;

	renderer_base_t () : ptCorrectionShift (0, 0), bOverlay (false) {}
	virtual ~renderer_base_t () {}

	void swap (renderer_base_t & _other);

	virtual bool IsImage () const {return false;}
	virtual long Width  () const = 0;
	virtual long Height () const = 0;
	virtual void Draw (HDC _hDC, const rect_t & _rectVisible, int _nShiftX, int _nShiftY) const = 0;
};

typedef std::list<renderer_base_t *> renderers_t;

class CMapRenderer;
struct map_renderer_t : public renderer_base_t {
  private:
	// Disable copy semantics.
	map_renderer_t (const map_renderer_t &);
	void operator = (const map_renderer_t &);

  public:
	map_renderer_t () : pMapRenderer (NULL) {}
	map_renderer_t (CMapRenderer * _pMapRenderer);
	~map_renderer_t ();

	void swap (map_renderer_t & _other);

	// Override.
	virtual long Width  () const {return lWidth;}
	virtual long Height () const {return lHeight;}
	virtual void Draw (HDC _hDC, const rect_t & _rectVisible, int _nShiftX, int _nShiftY) const;

	virtual void * DetachData ();
	virtual void AttachData (void * _pData);
	virtual void FreeData   (void * _pData);

  private:
	CMapRenderer * pMapRenderer;
	long lWidth;
	long lHeight;
};


# include "Bitmap.h"

//
// The attached raster map.
//
struct image_t : public renderer_base_t {
	CCPtr<CBitmap> pBitmap;
	CCPtr<CBitmap> pBitmapSmall;

	image_t () {}
	image_t (CBitmap * _pBitmap);

	void MakeSmall ();

	void swap (image_t & _other);

	// Override.
	virtual void * DetachData ();
	virtual void AttachData (void * _pData);
	virtual void FreeData   (void * _pData);

	virtual bool IsImage () const {return true;}
	virtual long Width  () const {return pBitmap ? pBitmap->Width  () : 0;}
	virtual long Height () const {return pBitmap ? pBitmap->Height () : 0;}
	virtual void Draw (HDC _hDC, const rect_t & _rectVisible, int _nShiftX, int _nShiftY) const;
};

void JoinRenderers (renderers_t & _renderers1, renderers_t & _renderers2);
void UpdateOverlays (renderers_t & _renderers);
bool IsRenderer (const map_t & _map, const file_ref_t & _fr);


//
// The data returned by map_t::Find(): either object or image under a given point.
//
struct find_info_t {
	// NULL if not found.
	layer_t * pLayer;
	rgns_t::iterator iRgn;
	// -1 for all rgn' elements.
	size_t cElementOrOrigin;
	// The nearest node of polyline/polygon.
	size_t cPoint;
	// The nearest point on the rgn's border.
	point_t ptNearest;

	// NULL if not found.
	renderer_base_t * pRenderer;

	find_info_t () : pLayer (NULL), pRenderer (NULL), cPoint (-1) {}

	void clear () {
		pLayer    = NULL;
		pRenderer = NULL;
	}

	bool empty () const {return pRenderer == NULL && pLayer == NULL;}

	bool operator == (const find_info_t & _other) const {
		if (pRenderer != NULL || _other.pRenderer != NULL)
			return pRenderer == _other.pRenderer;
		if (pLayer != _other.pLayer)
			return false;
		if (pLayer == NULL)
			return true;
		return iRgn == _other.iRgn && cElementOrOrigin == _other.cElementOrOrigin;
	}
};

	// The precision of rgn search.
const float c_fE_in_pixels = 4;


//
// The map header.
//

enum CCodeSchema_t {
	bpsAscii7 = 6,
	bpsSBCS   = 9,
	bpsMBCS   = 10
};

struct map_header_t {
	string_t strID;
	string_t strName;

	WORD     wCodePage;
	CCodeSchema_t CodeSchema;

	elevation_units_t  ElevationUnits;

	//
	// NOTE: the attributes which are specific for cgpsmapper.exe.
	//
	enum preprocess_t {ppNo, ppGeneralization, ppFull};
	preprocess_t Preprocess;

	size_t cTreSize;
	float  fTreMargin;

	size_t cRgnLimit;

	bool bTransparent;

	//
	// NOTE: the attributes which are specific for commercial version of cgpsmapper.exe.
	//
	bool bPOIIndex;
	bool bPOINumberFirst;
	bool bPOIZipFirst;

	bool bMG;        // lock on road, search for intersection and show next street name active
	bool bNumbering; // lock on road and show next street name and house numbers along street active
	bool bRouting;   // lock on road and show next street name active, house numbers along street and routable maps active
	bool bInvisible; // map is invisible. This is used for routing only maps.
	string_t strCopyright;

	//
	// The unsupported rest of definitions.
	//
	typedef std::map<string_t, string_t> extra_t;
	extra_t extra;

	map_header_t () {clear ();}

	void clear ();
	void swap (map_header_t & _other);

	bool operator == (const map_header_t & _other) const;
};


//
// Sections which are not supported directly are stored as raw text.
//
struct section_t {
	string_t strText;
};

typedef std::list<section_t> sections_t;

//
// The map zoom level data.
//
struct map_level_t {
	bool operator == (const map_level_t & _other) const {
		return btBits == _other.btBits && btBitsRangeTo == _other.btBitsRangeTo;
	}

	void SetBasicScale (BYTE _btBits) {
		btBits        = _btBits;
		btBitsRangeTo = _btBits;
	}

	BYTE btBits;         // Bits used to store position x or y.
	BYTE btBitsRangeTo;  // Affects the scale (referred in bits) this level should be extended to (btBits >= btBitsRangeTo)

	size_t cZoom;        // Ordinal for Garmin MapSource only.

	map_level_t () : cZoom (0) {}
};
typedef std::vector<map_level_t> map_levels_t;

class CMapLoader;
class CTransformationBase;

struct mta_transform_t;


//
// The map data.
//
struct map_t {
	//
	// Header data.
	//

	// True for imported maps w/o [IMG ID] headers.
	bool bNoHeader;
	// The length of the header in source file in bytes.
	size_t cHeaderLen;
	// The header itself.
	map_header_t Header;

	// The zoom levels.
	map_levels_t Levels;


	//
	// The sections which are not supported directly are stored here.
	//
	sections_t ExtraSections;


	//
	// The data for object's extra attributes.
	//
	countries_t Countries;
	regions_t   Regions;
	cities_t    Cities;
	zips_t      Zips;
	highways_t  Highways;

	//
	// The type set.
	//
	const CTypeSet * pTypeSet;


	//
	// The map layers sorted in reverse order of drawing:
	//   layers[rkPoint]    is for points,
	//   layers[rkPolyline] is for polylines,
	//   layers[rkPolygon]  is for polygons, in turn, sorted by fAveElementArea.
	//
	layer_t layers [rkMax];


	// The raster images attached.
//	images_t images;

	renderers_t renderers;

	// Source files (including attached files with waypoints and tracks but excluding raster maps).
	file_refs_t file_refs;

	// Routing graph data.
	rgnodes_t rgnodes;
	rgrestrictions_t rgrestrictions;

	bool bDirtyRGNodes;
	void CountRGNodes (bool _bEnforce = true);

	DWORD dwMaxNodeID;
	rgnode_t & CreateNode (DWORD _dwNodeID);
	rgnode_t & CreateNode ();
	rgnode_t * FindExternalNode (const point_t & _pt);
	bool HasNode (DWORD _dwNodeID) const;
	void MakeSureAllNodeIDsAreUnique ();

	DWORD dwMaxRoadID;
	void SetRoadID (rgn_t & _rgn);
	void SetRoadID (rgn_t & _rgn, DWORD _dwRoadID);
	void MakeSureAllRoadIDsAreUnique ();


	// The bounding rectangle for the whole map.
	rect_t rectBound;
	// Max number of points per rgn's element.
	size_t cMaxPointsInElement;
	// Cosine of the average map's latitude.
	float fCosY;


	// The head & tail of rgns list in load order.
	rgn_t * pFirstRgn, * pLastRgn;
	void InsertRgnToSaveList (rgn_t & _rgn) {
		if (pFirstRgn == NULL)
			pFirstRgn = & _rgn;
		if (pLastRgn != NULL)
			pLastRgn->pNextRgn = & _rgn;
		pLastRgn = & _rgn;
	}
	void SpliceSaveLists (map_t & _other) {
		if (pFirstRgn == NULL) {
			pFirstRgn = _other.pFirstRgn;
			assert (pLastRgn == NULL);
			pLastRgn  = _other.pLastRgn;
		} else {
			if (pLastRgn)
				pLastRgn->pNextRgn = _other.pFirstRgn;
			if (_other.pLastRgn)
				pLastRgn = _other.pLastRgn;
		}
		_other.pFirstRgn = NULL;
		_other.pLastRgn = NULL;
	}


	// The number of significant digits (for load/save).
	size_t cPrecOrder;


	// The constructor.
	map_t () {clear ();}
	void clear ();

	bool empty () const {
		return
			layers [rkPoint]   .rgns.empty () &&
			layers [rkPolyline].rgns.empty () &&
			layers [rkPolygon] .rgns.empty () &&
			renderers.empty ();
//			images.empty ();
	}
	size_t GetRgnCount () const {
		return layers [rkPoint].cRgns + layers [rkPolyline].cRgns + layers [rkPolygon].cRgns;
	}

	rgn_t & CreateRgn (RGN_KIND _Kind);
	rgns_t::iterator CreateRgnIt (RGN_KIND _Kind);

	LoadStatus_t LoadMap (const char * _pData, size_t _cFileSize, const char * _strFileName, CMapLoader * _pLoader);

	map_t & operator = (const map_t & _other);

	void swap (map_t & _other);
	void Join (map_t & _other);

	void RefreshDrawOrder () {
		layers [rkPolygon].rgns.sort ();//CompareRgnArea ());
		// NOTE: in some cases, MS STL implementation of list<>::sort() loses some of objects!
		// Please use STLPort instead to avoid this bug.
		assert (layers [rkPolygon].rgns.size () == layers [rkPolygon].cRgns);
	}

	size_t occupied () const;

	find_info_t Find (const point_t & _pt, const rgn_t * _pExceptRgn = 0);

	void Draw (HDC _hDC, const rect_t & _rect, size_t _cProgressStart, size_t _cProgressEnd, bool _bShowAttachments) const;

	// Apply an affine transformation to all points and other rgn's attributes.
	void Transform (const aff_transform_t & _at);
	// Apply a quadratic transformation to all points and other rgn's attributes.
	void Transform (const q_transform_t   & _qt);
	// Apply a d-transformation to all points and other rgn's attributes.
	void Transform (const mta_transform_t & _tt);
	// Apply the given transform to all points.
	// NOTE: other rgn's attributes are not touched.
	void TransformPoints (const CTransformationBase & _Transformation);

  private:
	void _UpdateLevels (const std::vector<size_t> & _Old2New);
	static void _MakeLevelsEqual (map_t & _map1, map_t & _map2);

	bool _HasTextualData () const;

  public:
	void RemovePAIDuplicates ();
};


//
// The map in hand.
//
extern map_t g_map;

// The critical section to protect access to g_map.
# include "Wrappers.h"
extern CCritSec g_cs;

# endif // __Map_H_